﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace Atosenet.IO
{
    public abstract class BaseIO : IDisposable
    {
        #region 成员

        public event RawDataReceivedEventHandler RawDataReceived;
        public event IOOpenedEventHandler Opened;
        public event IOClosedEventHandler Closed;
        public event IOFailedEventHandler Failed;
        public event ClientIOAddedEventHandler ClientIOAdded;
        public event ClientIORemovedEventHandler ClientIORemoved;

        #endregion


        #region 初始化

        public BaseIO(IOParameter param)
        {
            GenerateID();
            IsInitialized = false;
            IOParam = param;
            IsInitialized |= ApplyParameter();
            IsInitialized &= Initialize();
        }

        protected virtual bool Initialize()
        {
            if (IOParam == null)
                return false;

            Clients = new ClientIOCollection(this);
            IOParam.ParameterChanged -= new EventHandler(IOParam_ParameterChanged);
            IOParam.ParameterChanged += new EventHandler(IOParam_ParameterChanged);
            return true;
        }

        private void GenerateID()
        {
            ID = RandomGenerator.Next(1, 9999);
        }

        #endregion


        #region 公开函数

        public abstract bool Open();

        public abstract bool Close();

        public abstract bool Close(int id);

        public abstract int Write(byte[] buffer, int offset, int length);

        public abstract int WriteTo(int id, byte[] buffer, int offset, int length);

        public abstract bool ApplyParameter();

        public virtual void Dispose()
        {
            Close();
        }

        #endregion


        #region 静态函数

        public static BaseIO CreateInstance(IOParameter para)
        {
            if (TypeManager.Plugins.Count == 0 || para == null)
                return null;

            return TypeManager.CreateInstance(para.IOName, para) as BaseIO;
        }

        public static bool TryCreateInstance(IOParameter para, out BaseIO result)
        {
            result = CreateInstance(para);
            return result != null;
        }

        public static bool IsNullOrInvalid(BaseIO io)
        {
            return io == null || io.IOParam == null;               
        }

        #endregion


        #region 内部函数
        
        protected virtual void IOParam_ParameterChanged(object sender, EventArgs e)
        {
            ApplyParameter();
        }

        #endregion


        #region 属性

        public int ID
        {
            get;
            private set;
        }

        public ClientIOCollection Clients
        {
            get;
            private set;
        }

        public virtual IOModeType IOMode
        {
            get { return IOModeType.None; }
        }

        public IOParameter IOParam
        {
            get;
            private set;
        }

        public bool IsInitialized
        {
            get;
            private set;
        }

        public bool IsOpened
        {
            get;
            private set;
        }

        #endregion


        #region 事件

        protected void OnRawDataReceived(IOErrorType errorType)
        {
            if (RawDataReceived != null)
            {
                RawDataReceivedEventArgs e = new RawDataReceivedEventArgs(errorType);
                RawDataReceived(this, e);
            }
        }

        protected void OnRawDataReceived(byte[] data)
        {
            if (RawDataReceived != null)
            {
                RawDataReceivedEventArgs e = new RawDataReceivedEventArgs(data, ID);
                RawDataReceived(this, e);
            }
        }

        protected void OnRawDataReceived(byte[] data, int clientId)
        {
            if (RawDataReceived != null)
            {
                RawDataReceivedEventArgs e = new RawDataReceivedEventArgs(data, clientId, ID);
                RawDataReceived(this, e);
            }
        }

        protected void OnIOOpened(int clientId)
        {
            if (Opened != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(clientId, ID);
                Opened(this, e);
            }
            IsOpened = true;
        }

        protected void OnIOOpened()
        {
            if (Opened != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(ID);
                Opened(this, e);
            }
            IsOpened = true;
        }

        protected void OnIOClosed(int clientId)
        {
            if (Closed != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(clientId, ID);
                Closed(this, e);
            }
            IsOpened = false;
        }

        protected void OnIOClosed()
        {
            if (Closed != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(ID);
                Closed(this, e);
            }
            IsOpened = false;
        }

        protected void OnIOFailed(int clientId, int errorCode)
        {
            if (Failed != null)
            {
                IOFailedEventArgs e = new IOFailedEventArgs(clientId, ID, errorCode);
                Failed(this, e);
            }
        }

        protected void OnIOFailed(int errorCode)
        {
            if (Failed != null)
            {
                IOFailedEventArgs e = new IOFailedEventArgs(ID, 0, errorCode);
                Failed(this, e);
            }
        }

        protected void OnClientIOAdded(int clientId)
        {
            if (ClientIOAdded != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(clientId, ID);
                ClientIOAdded(this, e);
            }
        }

        protected void OnClientIORemoved(int clientId)
        {
            if (ClientIORemoved != null)
            {
                IOStatusEventArgs e = new IOStatusEventArgs(clientId, ID);
                ClientIORemoved(this, e);
            }
        }

        #endregion


        #region 附加对象

        public class ClientIOCollection
        {
            #region 成员

            

            #endregion


            #region 初始化

            public ClientIOCollection(BaseIO parent)
            {
                ClientIOs = new List<ClientIO>();
                ParentIO = parent;
                HostID = parent.ID;
            }

            #endregion


            #region 公开函数

            public ClientIO Find(int id)
            {
                return ClientIOs.Find(io => { return io.ID == id; });
            }

            public ClientIO Find(IPEndPoint address)
            {
                return ClientIOs.Find(io => { return io.Address.Address.ToString() == address.Address.ToString() && io.Address.Port == address.Port; });
            }

            public bool Contains(int id)
            {
                return Find(id) != null;
            }

            public bool Contains(IPEndPoint address)
            {
                return Find(address) != null;
            }

            public int Add(ClientIO io)
            {
                if (!ClientIOs.Contains(io))
                {
                    io.TcpDataReceived += IO_TcpDataReceived;
                    io.TcpDisconnected += IO_TcpDisconnected;
                    ClientIOs.Add(io);
                    ParentIO.OnClientIOAdded(io.ID);
                    return io.ID;
                }
                return -1;
            }

            public int Add(IPEndPoint address)
            {
                ClientIO io = new ClientIO(HostID, address);
                return Add(io);
            }

            public int Add(IPEndPoint address, Socket cSocket)
            {
                ClientIO io = new ClientIO(HostID, address, cSocket);
                return Add(io);
            }

            public bool Remove(int id)
            {
                ClientIO io = Find(id);
                return io == null ? false : Remove(io);
            }

            public bool Remove(ClientIO io)
            {
                io.Close();
                io.TcpDataReceived -= IO_TcpDataReceived;
                io.TcpDisconnected -= IO_TcpDisconnected;
                ParentIO.OnClientIORemoved(io.ID);
                return ClientIOs.Remove(io);
            }

            public void RemoveAll()
            {
                for (int i = this.ClientIOs.Count - 1; i >= 0; i--)
                {
                    Remove(ClientIOs[i]);
                }
            }

            #endregion


            #region 静态函数



            #endregion


            #region 核心函数

            private void IO_TcpDataReceived(object sender, ClientIOTcpReceivedEventArgs e)
            {
                ParentIO.OnRawDataReceived(e.Data, e.ID);
            }

            private void IO_TcpDisconnected(object sender, TcpClientConnectionFailedEventArgs e)
            {
                ParentIO.OnIOFailed(e.ID, e.ErrorCode);
            }

            #endregion


            #region 属性

            public BaseIO ParentIO
            {
                get;
                private set;
            }

            public int HostID
            {
                get;
                private set;
            }

            public ClientIO this[int index]
            {
                get
                {
                    if (index >= ClientIOs.Count)
                        return null;

                    return ClientIOs[index];
                }
            }

            public int Count
            {
                get { return ClientIOs.Count; }
            }

            private List<ClientIO> ClientIOs
            {
                get;
                set;
            }

            #endregion


            #region 事件



            #endregion
        }

        public class ClientIO
        {
            #region 成员

            public event ClientIOTcpReceivedEventHandler TcpDataReceived;
            public event TcpClientConnectionFailedEventHandler TcpDisconnected;

            private Thread _tcpReceiveThread;

            #endregion


            #region 初始化

            public ClientIO(int hostId, IPEndPoint address)
                : this(hostId, address, null)
            { }

            public ClientIO(int hostId, IPEndPoint address, Socket clientSocket)
            {
                HostID = hostId;
                ID = RandomGenerator.Next(1, 9999);
                Address = address;
                ClientSocket = clientSocket;
                Init();
            }

            private void Init()
            {
                if (ClientSocket != null)
                {
                    _tcpReceiveThread = new Thread(new ThreadStart(TcpReceiveProc));
                    _tcpReceiveThread.IsBackground = true;
                    _tcpReceiveThread.Name = "TcpReceive_Thread";
                    _tcpReceiveThread.Start();
                }
            }

            #endregion


            #region 公开函数

            public void Close()
            {
                if (ClientSocket == null)
                    return;

                try
                {
                    ClientSocket.Close(5);
                    _tcpReceiveThread.Abort();
                }
                catch
                { }
            }

            public override string ToString()
            {
                return string.Format("ID={0},ParentID={1},IP={2}", ID, HostID, Address.ToString());
            }

            public override bool Equals(object obj)
            {
                ClientIO b = obj as ClientIO;
                return b == null ? false : (this.Address.Address.ToString() == b.Address.Address.ToString() && this.Address.Port == b.Address.Port);
            }

            public override int GetHashCode()
            {
                return HostID * 10000 + ID;
            }

            #endregion


            #region 静态函数



            #endregion


            #region 核心函数

            private void TcpReceiveProc()
            {
                try
                {
                    while (true)
                    {
                        ClientSocket.Blocking = true;
                        byte[] received = new byte[1024 * 128];
                        int rCount = ClientSocket.Receive(received);

                        if (rCount == 0)
                        {
                            OnTcpDisconnected(ID, 0);
                            return;
                        }

                        byte[] data = new byte[rCount];
                        Array.Copy(received, 0, data, 0, data.Length);

                        OnDataReceived(data);
                    }
                }
                catch(SocketException e)
                {
                    OnTcpDisconnected(ID, e.ErrorCode);
                    InternalTrace.TraceError("TCP通信错误(Server)，错误信息：{0}，错误号：{1}，堆栈:{2}。", e.Message, e.ErrorCode, e.StackTrace);
                }
            }

            #endregion


            #region 属性

            public IPEndPoint Address
            {
                get;
                private set;
            }

            public int HostID
            {
                get;
                private set;
            }

            public int ID
            {
                get;
                private set;
            }

            public Socket ClientSocket
            {
                get;
                private set;
            }

            public bool IsAlive
            {
                get
                {
                    return ClientSocket == null ? true : _tcpReceiveThread.ThreadState == ThreadState.Running;
                }
            }

            #endregion


            #region 事件

            private void OnDataReceived(byte[] data)
            {
                if (TcpDataReceived != null)
                {
                    ClientIOTcpReceivedEventArgs e = new ClientIOTcpReceivedEventArgs(ID, data);
                    TcpDataReceived(this, e);
                }
            }

            private void OnTcpDisconnected(int id, int errorCode)
            {
                if (TcpDisconnected != null)
                {
                    TcpClientConnectionFailedEventArgs e = new TcpClientConnectionFailedEventArgs(id, errorCode);
                    TcpDisconnected(this, e);
                }
            }

            #endregion
        }

        public delegate void ClientIOTcpReceivedEventHandler(object sender, ClientIOTcpReceivedEventArgs e);

        public class ClientIOTcpReceivedEventArgs : EventArgs
        {
            public byte[] Data;
            public int ID;

            public ClientIOTcpReceivedEventArgs(int id, byte[] data)
            {
                Data = data;
                ID = id;
            }
        }

        public delegate void TcpClientConnectionFailedEventHandler(object sender, TcpClientConnectionFailedEventArgs e);

        public class TcpClientConnectionFailedEventArgs : EventArgs
        {
            public int ID;
            public int ErrorCode;

            public TcpClientConnectionFailedEventArgs(int id, int errorCode)
            {
                ID = id;
                ErrorCode = errorCode;
            }
        }

        #endregion
    }


    [Flags]
    public enum IOErrorType
    {
        None = 0x00,
        ReadError = 0x01,
        WriteError = 0x02,
        ReadOrWriteError = ReadError | WriteError
    }

    public delegate void RawDataReceivedEventHandler(object sender, RawDataReceivedEventArgs e);

    public class RawDataReceivedEventArgs : EventArgs
    {
        public IOErrorType ErrorType = IOErrorType.None;
        public byte[] Data = new byte[] { };
        public int ID;
        public int HostID = 0;
        public DateTime Timestamp;

        public RawDataReceivedEventArgs(byte[] data, int id)
        {
            ErrorType = IOErrorType.None;
            Data = data;
            ID = id;
            Timestamp = DateTime.Now;
        }

        public RawDataReceivedEventArgs(byte[] data, int id, int hostId)
        {
            ErrorType = IOErrorType.None;
            Data = data;
            ID = id;
            HostID = hostId;
            Timestamp = DateTime.Now;
        }

        public RawDataReceivedEventArgs(IOErrorType eventType)
        {
            ErrorType = eventType;
            Timestamp = DateTime.Now;
        }

        public bool IsClientMode
        {
            get { return HostID > 0; }
        }
    }

    public delegate void IOOpenedEventHandler(object sender, IOStatusEventArgs e);

    public delegate void IOClosedEventHandler(object sender, IOStatusEventArgs e);

    public delegate void IOFailedEventHandler(object sender, IOFailedEventArgs e);

    public delegate void ClientIOAddedEventHandler(object sender, IOStatusEventArgs e);
    public delegate void ClientIORemovedEventHandler(object sender, IOStatusEventArgs e);

    public class IOStatusEventArgs : EventArgs
    {
        public int ID;
        public int HostID = 0;
        public DateTime Timestamp;

        public IOStatusEventArgs(int id, int hostId)
        {
            ID = id;
            HostID = hostId;
            Timestamp = DateTime.Now;
        }

        public IOStatusEventArgs(int id)
        {
            ID = id;
            Timestamp = DateTime.Now;
        }

        public bool IsClientIO
        {
            get { return HostID != 0; }
        }
    }

    public class IOFailedEventArgs : IOStatusEventArgs
    {
        public int ErrorCode;

        public IOFailedEventArgs(int id, int hostId, int errorCode)
            : base(id, hostId)
        {
            ErrorCode = errorCode;
        }
    }
}
